package net

import (
	"encoding/json"
	"fmt"
	"github.com/forgoer/openssl"
	"github.com/gorilla/websocket"
	"log"
	"mssgserver/utils"
	"sync"
)

// wsServer websocket服务
type wsServer struct {
	wsConn       *websocket.Conn
	router       *router
	outChan      chan *WsMsgRep         //写队列
	Seq          int64                  // 序列
	property     map[string]interface{} //属性
	propertyLock sync.RWMutex           // 属性读写锁
}

func NewWsServer(wsConn *websocket.Conn) *wsServer {
	return &wsServer{
		wsConn:   wsConn,
		outChan:  make(chan *WsMsgRep, 1000),
		property: make(map[string]interface{}),
		Seq:      0,
	}
}

func (w *wsServer) Router(router *router) {
	w.router = router
}

func (w *wsServer) SetProperty(key string, value interface{}) {
	// 加锁
	w.propertyLock.Lock()
	// 解锁
	defer w.propertyLock.Unlock()
	w.property[key] = value
}

func (w *wsServer) GetProperty(key string) (interface{}, error) {
	// 加锁 读锁
	w.propertyLock.RLock()
	// 解锁 读锁
	defer w.propertyLock.RUnlock()
	return w.property[key], nil
}
func (w *wsServer) RemoveProperty(key string) {
	// 加锁 写锁
	w.propertyLock.Lock()
	// 解锁 写锁
	defer w.propertyLock.Unlock()
	delete(w.property, key)
}
func (w *wsServer) Addr() string {
	return w.wsConn.RemoteAddr().String()
}
func (w *wsServer) Push(name string, data interface{}) {
	rsp := &WsMsgRep{Body: &RepBody{
		Seq:  0,
		Name: name,
		Msg:  data,
	}}
	w.outChan <- rsp
}

// 通道一旦建立 那么收发消息 就得要一直箭头才行
func (w *wsServer) Start() {
	// 启动读写数据的处理逻辑
	go w.readMsgLoop()
	go w.writeMsgLoop()
}

func (w *wsServer) readMsgLoop() {
	// 先读到客户端 发送过来的数据 然后进行处理 然后在回消息
	// 经过路由 时间处理程序
	defer func() {
		if err := recover(); err != nil {
			log.Fatal(err)
			w.Close()
		}
	}()

	for {
		_, data, err := w.wsConn.ReadMessage()
		if err != nil {
			log.Println("websocket收消息出现错误", err)
			break
		}
		// 收到消息 解析消息 前段发送过来的消息 就是json格式
		// 1.data 进行解压 unzip
		data, err = utils.UnZip(data)
		if err != nil {
			log.Println("解压数据出错,非法格式", err)
			continue
		}
		// 2.前端的消息 加密消息 进行解密
		secretKey, err := w.GetProperty("`secretKey`")
		if err == nil {
			// 有加密
			key := secretKey.(string)
			// 客户端传输过来的数据是加密的  需要解密
			d, err := utils.AesCBCDecrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING)
			if err != nil {
				log.Println(err)
				// 出错误 发起握手
				// w.Handshake()
			} else {
				data = d
			}
		}
		// 3.data 转为 body
		body := &ReqBody{}
		err = json.Unmarshal(data, body)
		if err != nil {
			log.Println("数据格式错误 非法格式: ", err)
		} else {
			// 获取到前端传递的数据 那是这些数据 去具体的业务进行处理
			req := &WsMsgReq{Conn: w, Body: body}
			rsp := &WsMsgRsp{Body: &RepBody{Seq: req.Body.Seq, Name: body.Name}}
			w.router.Run(req, rsp)

			w.outChan <- rsp
		}
	}
	w.Close()
}

func (w *wsServer) writeMsgLoop() {

	for {
		select {
		case msg := <-w.outChan:
			fmt.Println(msg)
		}
	}

}

func (w *wsServer) Close() {
	_ = w.wsConn.Close()
}
